﻿using System;
using System.Collections.Generic;
using System.Text;
using FieldLib;
using FieldDevice.Emulation;
using System.Collections;

namespace FieldDevice.ModBus
{
    public class ModBusIO
    {
        public FieldLib.Channel Channel;
        public bool IsEmulation = false;
        public  ModBusIO()
        {
            if(FieldLib.SystemConfig.GlobalSystemConfig.DeviceEmulation== FieldLib.SystemConfig.EnumDeviceEmulation.Emulation)
                CreateDeviceEmulators();
        }

       SortedList<ushort, DeviceEmulator> DeviceEmulators = new SortedList<ushort, DeviceEmulator>();

       public DeviceEmulator GetDeviceEmulator(ushort address)
       {
           return this.DeviceEmulators[address];
       }
       void CreateDeviceEmulators()
       {
           this.DeviceEmulators.Add(7, new ACR120ELEmulator(7));
           this.DeviceEmulators.Add(1, new PM800Emulator(1));


       }
      
        //private ModBusPacket Response;
        private byte[] ModBuf = new byte[520];
        #region //CRC校验
        public static  ModBusPacket CRCVerify(ModBusPacket verify)
        {
            ModBusPacket tmpMod = verify;
            byte CRCHi = 0xFF;
            byte CRCLo = 0xFF;
            byte CL = 0x01;
            byte CH = 0xA0;
            byte SaveHi; 
            byte SaveLo;
            CRCLo^=verify.DataAddressLow;
            for (int Flag = 0; Flag <= 7; Flag++)
            {
                SaveHi = CRCHi;
                SaveLo = CRCLo;
                CRCHi = (byte)(CRCHi >> 1);      //高位右移一位 
                CRCLo = (byte)(CRCLo >> 1);      //低位右移一位 
                if ((SaveHi & 0x01) == 0x01) //如果高位字节最后一位为1 
                    {
                        CRCLo = (byte)(CRCLo | 0x80);   //则低位字节右移后前面补1 
                    }             //否则自动补0 
                if ((SaveLo & 0x01) == 0x01) //如果LSB为1，则与多项式码进行异或 
                    {
                        CRCHi = (byte)(CRCHi ^ CH);
                        CRCLo = (byte)(CRCLo ^ CL);
                    }
            }

            CRCLo ^= verify.DataAddressHi;
            for (int Flag = 0; Flag <= 7; Flag++)
            {
                SaveHi = CRCHi;
                SaveLo = CRCLo;
                CRCHi = (byte)(CRCHi >> 1);      //高位右移一位 
                CRCLo = (byte)(CRCLo >> 1);      //低位右移一位 
                if ((SaveHi & 0x01) == 0x01) //如果高位字节最后一位为1 
                {
                    CRCLo = (byte)(CRCLo | 0x80);   //则低位字节右移后前面补1 
                }             //否则自动补0 
                if ((SaveLo & 0x01) == 0x01) //如果LSB为1，则与多项式码进行异或 
                {
                    CRCHi = (byte)(CRCHi ^ CH);
                    CRCLo = (byte)(CRCLo ^ CL);
                }
            }


            CRCLo ^= verify.DataNumberLow;
            for (int Flag = 0; Flag <= 7; Flag++)
            {
                    SaveHi = CRCHi;
                    SaveLo = CRCLo;
                    CRCHi = (byte)(CRCHi >> 1);      //高位右移一位 
                    CRCLo = (byte)(CRCLo >> 1);      //低位右移一位 
                    if ((SaveHi & 0x01) == 0x01)       //如果高位字节最后一位为1 
                    {
                        CRCLo = (byte)(CRCLo | 0x80);   //则低位字节右移后前面补1 
                    }                                   //否则自动补0 
                    if ((SaveLo & 0x01) == 0x01)    //如果LSB为1，则与多项式码进行异或 
                    {
                        CRCHi = (byte)(CRCHi ^ CH);
                        CRCLo = (byte)(CRCLo ^ CL);
                    }
              }


            CRCLo ^= verify.DataNumberHi;
            for (int Flag = 0; Flag <= 7; Flag++)
            {
                SaveHi = CRCHi;
                SaveLo = CRCLo;
                CRCHi = (byte)(CRCHi >> 1);      //高位右移一位 
                CRCLo = (byte)(CRCLo >> 1);      //低位右移一位 
                if ((SaveHi & 0x01) == 0x01) //如果高位字节最后一位为1 
                {
                    CRCLo = (byte)(CRCLo | 0x80);   //则低位字节右移后前面补1 
                }             //否则自动补0 
                if ((SaveLo & 0x01) == 0x01)     //如果LSB为1，则与多项式码进行异或 
                {
                    CRCHi = (byte)(CRCHi ^ CH);
                    CRCLo = (byte)(CRCLo ^ CL);
                }
            }
            tmpMod.CRCH = CRCHi;
            tmpMod.CRCL = CRCLo;

            return tmpMod;
        }
#endregion
        public ModBusPacket SendReceive(ModBusPacket frame)
        {
            throw new Exception("No reponse!");
        }
        public void Send(Device sender, ModBusPacket frame)
        {
            //ModScan32中CRC计算结果为01 03 04 63 00 01 c4 e5
            //与本算法一致
   //        ModBusPacket frame2 = CRCVerify(frame);
            if (IsEmulation)
            {
           //     ModBusPacket frame2 = CRCVerify(frame);
                DeviceEmulator emulator = this.DeviceEmulators[frame.SlaveAddress];
                ModBuf = emulator.ProcessModBusPacket(frame);
            }
            else
            {
                byte[] buffer = frame.ToBytes();
                byte CRCHigh;
                byte CRCLow;
                CRC.CRC16(buffer, buffer.Length - 2, out CRCHigh, out CRCLow);
                buffer[buffer.Length - 2] = CRCHigh;
                buffer[buffer.Length - 1] = CRCLow;
                //  this.Channel.Send(buffer, 0x00010101, 0x10010101);
                sender.SerialPort.Send(buffer, 0x00010101, sender.NCPAddress);
            }
        }

        public byte[] Receive(Device sender)
        {
            byte[] packet;//variable to represent fully assembled packet
            for (int i = 0; i < 5; i++)
            {
                byte[] netresult = null;
                if (this.IsEmulation)
                    netresult = this.Channel.Receive();
                else
                    netresult = sender.SerialPort.Receive(sender);
               
                FieldLib.Comm.Frame ncpframe = FieldLib.Comm.Frame.FromBytes(netresult);
                byte[] result = ncpframe.content;
               
                if (sender.IsPacketFinished(netresult, out packet))
                    return packet;
            }
            //Response = new ModBusPacket();
            //Response.SlaveAddress = result[0];
            return null;
        }
       
    }
}
